#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <iostream>
#include <string>
#include <nlohmann/json.hpp>

using std::cout;
using std::cin;
using std::string;
using Json = nlohmann::json;

typedef struct train_s{
    int length; //该长度为json的长度
    int type;
    string jsonObj;
}train_t;

void sendTrain(int sockfd,const train_t& train){
        //将train发送给服务端
        int length = train.length;
        int type = train.type;
        string content = train.jsonObj;
        send(sockfd,&length,sizeof(train.length),0);
        send(sockfd,&type,sizeof(train.type),0);
        send(sockfd,content.c_str(),train.jsonObj.size(),0);
}

int readn(int netfd,char * buf, int len) {
    int left = len; //剩余要读的字节数
    char *pstr = buf;   
    int ret = 0;
    while(left > 0){
        ret = read(netfd,pstr,left);
        if(-1 == ret && errno == EINTR){
            continue;
        }else if(-1 == ret){
            perror("read error -1");
            exit(1);
        }else if(0 == ret){
            break;
        }else{
            pstr += ret;
            left -= ret;
        }
    }
    return len - left;
}

void readTrain(int netfd,train_t& train){
    int length = 0;
    readn(netfd,(char*)&length,sizeof(train.length));
    train.length = length;
    int type = 0;
    readn(netfd,(char*)&type,sizeof(train.type));
    train.type = type;
    train.jsonObj.reserve(train.length);
    char* content = (char*)malloc(train.length+1);
    bzero(content,train.length+1);
    readn(netfd,content,train.length);
    train.jsonObj = string(content);
    free(content);
    return ;
}

int main(int argc,char*argv[])
{
    // ./client 192.168.30.128 1234
     
    int sockfd = socket(AF_INET,SOCK_STREAM,0);
    struct sockaddr_in addr;
    bzero(&addr,sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = inet_addr(argv[1]);
    addr.sin_port = htons(atoi(argv[2]));
    int ret = connect(sockfd,(struct sockaddr*)&addr,sizeof(addr));
    if(errno != 0){
        perror("error:");
    }

    // 处理业务
    int type;
    do{
        cout << "1.关键字推荐,2.网页搜索,0.退出.\n";
        std::cerr << "请输入要进行的操作:";
        cin >> type; //输入类型
        if(type == 0){
            break;
        }
        std::cerr << "请输入关键字或者网页内容:";
        string query;
        cin >> query;
        //构建JsonObj
        Json jsonObj;
        jsonObj["query"] = query;
        //构建train
        train_t train;
        train.jsonObj = jsonObj.dump();
        train.length = train.jsonObj.size();
        train.type = type;
        //将train发送给服务端
        sendTrain(sockfd,train);
        cout << "train.length = " << train.length <<std::endl;
        cout << "train.type = " << train.type <<std::endl;
        cout << "train.jsonObj = " << train.jsonObj <<std::endl;
        //接收服务端的信息
        train_t train1;
        readTrain(sockfd,train);
        cout << "train.jsonObj = " << train.jsonObj <<"\n";
    }while(1);
    close(sockfd);
    return 0;
}
